package bg.btanev.eightyfour.repository.impl;

import java.util.List;

import org.apache.commons.lang.Validate;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import bg.btanev.eightyfour.dao.GenericDAO;
import bg.btanev.eightyfour.domain.experience.EducationExperience;
import bg.btanev.eightyfour.domain.experience.ExperiencePeriod;
import bg.btanev.eightyfour.domain.experience.WorkExperience;
import bg.btanev.eightyfour.domain.experience.institution.EducationInstitution;
import bg.btanev.eightyfour.domain.experience.institution.WorkInstitution;
import bg.btanev.eightyfour.domain.person.ContactInfo;
import bg.btanev.eightyfour.domain.person.Person;
import bg.btanev.eightyfour.domain.person.PersonName;
import bg.btanev.eightyfour.repository.PersonRepository;

/**
 *
 * @author B.Tanev
 *
 */
public class PersonRepositoryImpl implements PersonRepository {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = LoggerFactory.getLogger(PersonRepositoryImpl.class);

	private GenericDAO<Long, WorkExperience> workExperienceDAO;
	private GenericDAO<Long, EducationExperience> educationExperienceDAO;
	private GenericDAO<Long, Person> personDAO;

	public PersonRepositoryImpl() {
	}

	public void setWorkExperienceDAO(GenericDAO<Long, WorkExperience> workExperienceDAO) {
		this.workExperienceDAO = workExperienceDAO;
	}

	public void setEducationExperienceDAO(GenericDAO<Long, EducationExperience> educationExperienceDAO) {
		this.educationExperienceDAO = educationExperienceDAO;
	}

	public void setPersonDAO(GenericDAO<Long, Person> personDAO) {
		this.personDAO = personDAO;
	}

	@Override
	public EducationExperience createEducationExperience(ExperiencePeriod period, EducationInstitution institution, Person person,
			String speciality) {
		logger.debug("createEducationExperience(ExperiencePeriod, EducationInstitution, Person, String) - start"); //$NON-NLS-1$

		EducationExperience educationExperience = new EducationExperience(period, institution, person, speciality);

		educationExperienceDAO.saveUpdateEntity(educationExperience);

		logger.debug("createEducationExperience(ExperiencePeriod, EducationInstitution, Person, String) - end"); //$NON-NLS-1$
		return educationExperience;
	}

	@Override
	public WorkExperience createWorkExperience(ExperiencePeriod period, WorkInstitution institution, Person person,
			String position) {
		logger.debug("createWorkExperience(ExperiencePeriod, WorkInstitution, Person, String) - start"); //$NON-NLS-1$

		WorkExperience workExperience = new WorkExperience(period, institution, person, position);
		workExperienceDAO.saveUpdateEntity(workExperience);

		logger.debug("createWorkExperience(ExperiencePeriod, WorkInstitution, Person, String) - end"); //$NON-NLS-1$
		return workExperience;
	}

	@Override
	public Person createAndStorePerson(PersonName personName, ContactInfo contactInfo) {
		logger.debug("createAndStorePerson(PersonName, ContactInfo) - start"); //$NON-NLS-1$

		Person person = new Person(personName, contactInfo);
		storePerson(person);

		logger.debug("createAndStorePerson(PersonName, ContactInfo) - end"); //$NON-NLS-1$
		return person;
	}

	@Override
	public List<Person> findAllPersons() {
		logger.debug("findAllPersons() - start"); //$NON-NLS-1$

		List<Person> returnList = personDAO.findAll(false);

		logger.debug("findAllPersons() - end"); //$NON-NLS-1$
		return returnList;
	}

	@Override
	public void removePerson(Person person) {
		logger.debug("removePerson(Person) - start"); //$NON-NLS-1$

		personDAO.delete(person);

		logger.debug("removePerson(Person) - end"); //$NON-NLS-1$
	}

	@Override
	public void storePerson(Person person) {
		logger.debug("storePerson(Person) - start"); //$NON-NLS-1$

		personDAO.saveUpdateEntity(person);

		logger.debug("storePerson(Person) - end"); //$NON-NLS-1$
	}

	@Override
	public Person findByEmail(String email) {
		logger.debug("findByEmail(String) - start"); //$NON-NLS-1$

		Person returnPerson = personDAO.findByUniqueProperty("contactInfo.email", email);

		logger.debug("findByEmail(String) - end"); //$NON-NLS-1$
		return returnPerson;
	}

	@Override
	public List<Person> findByExactName(PersonName name) {
		logger.debug("findByExactName(PersonName) - start"); //$NON-NLS-1$

		Validate.notNull(name);

		DetachedCriteria detachedCriteria = personDAO.createDetachedCriteria();
		detachedCriteria.add(Restrictions.ilike("personName.firstName", name.getFirstName()));
		if (name.getSurName() != null) {
			detachedCriteria.add(Restrictions.ilike("personName.surName", name.getFirstName()));
		}
		detachedCriteria.add(Restrictions.ilike("personName.lastName", name.getLastName()));

		List<Person> returnList = personDAO.findByCriteria(detachedCriteria);

		logger.debug("findByExactName(PersonName) - end"); //$NON-NLS-1$

		return returnList;
	}

	@Override
	public List<Person> findByName(PersonName name) {
		logger.debug("findByName(PersonName) - start"); //$NON-NLS-1$

		Validate.notNull(name);

		DetachedCriteria detachedCriteria = personDAO.createDetachedCriteria();
		detachedCriteria.add(Restrictions.ilike("personName.firstName", name.getFirstName(), MatchMode.ANYWHERE));
		if (name.getSurName() != null) {
			detachedCriteria.add(Restrictions.ilike("personName.surName", name.getFirstName(), MatchMode.ANYWHERE));
		}
		detachedCriteria.add(Restrictions.ilike("personName.lastName", name.getLastName(), MatchMode.ANYWHERE));

		List<Person> returnList = personDAO.findByCriteria(detachedCriteria);

		logger.debug("findByName(PersonName) - end"); //$NON-NLS-1$

		return returnList;
	}

	@Override
	public Person findByIdentifier(Long personId) {
		return personDAO.findById(personId);
	}
}
